package it.jack.practicertmp;

import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;

import java.nio.ByteBuffer;

/**
 * @创建者 Jack
 * @创建时间 2022/7/6 11:05
 * @描述 音频数据的推送存在bug  后续再处理
 */
public class AudioCodec extends Thread {
    private MediaCodec  mediaCodec;
    //传输层
    private int         minBufferSize;
    private ScreenLive  screenLive;
    private boolean     isRecoding;
    private AudioRecord audioRecord;
    private long        startTime;

    public AudioCodec(ScreenLive screenLive) {
        this.screenLive = screenLive;
    }

    @SuppressLint("MissingPermission")
    public void startLive() {
        try {
            //配置音频硬编码器

            //44100的必须设置成2通道
            //创建一个 MediaFormat 对象，用于指定音频编码的格式。
            //MediaFormat.MIMETYPE_AUDIO_AAC 表示要使用AAC格式进行音频编码。
            //44100 是音频的采样率，表示每秒采集多少个音频样本。
            //2 表示音频的通道数，通常是立体声（左右两个通道）
            MediaFormat format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 44100, 2);

            //录音质量
//            format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            //录音质量低，dsp芯片就会使用低容量的buffer

            //设置AAC编码的配置参数，指定AAC配置的主要配置文件。
            //MediaCodecInfo.CodecProfileLevel.AVCProfileMain 表示使用主要的AAC配置文件。
            format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileMain);
            //语音码率
            //设置音频编码的比特率，这里设置为32 Kbps（千比特每秒）。
            format.setInteger(MediaFormat.KEY_BIT_RATE, 32*1024);

            //这里要设置成1，可能是bilibili需要这个参数设置成1（猜测）
            //设置音频编码的通道数，这里设置为1，表示单声道音频。
            format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
            //设置输入音频数据的最大大小，这里设置为8820字节。
            format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 8820);
            //创建一个音频编码器（MediaCodec）对象，指定编码器类型为AAC。
            mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

            //获取内部音频缓冲区的大小
            minBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
            mediaCodec.start();
            //            java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord.
            //                    at android.media.AudioRecord.startRecording(AudioRecord.java:1192)
            //动态权限没有开启的原因
            //参考：https://blog.csdn.net/qq_39312146/article/details/129423910
            //参数1，audioSource：音频采集的输入源
            //参数2，sampleRateInHz: 用于指定以多大的采样频率来采集音频，现在用的最多的兼容最好是 44100 (44.1KHZ)采样频率
            //参数3，channelConfig：该参数用于指定录音器采集几个声道的声音，可选值以常量的形式定义在 AudioFormat 类中，常用的值包括:
                //CHANNEL_IN_MONO 单声道 (移动设备上目前推荐使用)
                //CHANNEL_IN_STEREO 立体声
            //参数4，audioFormat: 采样格式，以常量的形式定义在 AudioFormat 类中，常用的值包括:
                //ENCODING_PCM_16BIT (16bit 兼容大部分 Android 手机)
                //ENCODING_PCM_8BIT (8bit)
            //参数5，bufferSizeInBytes: 配置内部音频缓冲区的大小(配置的缓存值越小，延时就越低)，而具体的大小，有可能在不同的手机上会有不同的值，那么可以使用 getMinBufferSize（API） 进行确定缓冲大小:
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize);
        } catch (Exception e) {
            e.printStackTrace();
        }
        start();
    }

    @Override
    public void run() {
        isRecoding = true;
        //1.开始录音
        audioRecord.startRecording();
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

        RTMPPackage rtmpPackage = new RTMPPackage();
        //这里的设置暂时有个印象就行
        byte[] audioDecoderSpecificInfo = {0x12, 0x08};//这里就当作规律，需要如此写即可
        rtmpPackage.setBuffer(audioDecoderSpecificInfo);
        rtmpPackage.setType(RTMPPackage.RTMP_PACKET_TYPE_AUDIO_HEAD);
        screenLive.addPackage(rtmpPackage);

        byte[] buffer = new byte[minBufferSize];
        while (isRecoding) {
            //2.提取数据
            int len = audioRecord.read(buffer, 0, buffer.length);
            if (len <= 0) {
                continue;
            }

            //立即得到有效输入缓冲区
            int index = mediaCodec.dequeueInputBuffer(1000);
            if (index >= 0) {
                ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);
                inputBuffer.clear();
                //format配置的问题
                //Process: com.maniu.rtmpmaniu, PID: 1929
                //    java.nio.BufferOverflowException
                //        at java.nio.DirectByteBuffer.put(DirectByteBuffer.java:298)
                //        at com.maniu.rtmpmaniu.AudioCodec.run(AudioCodec.java:94)
                inputBuffer.put(buffer, 0, len);
                //填充数据后再加入队列
                mediaCodec.queueInputBuffer(index, 0, len, System.nanoTime() / 1000, 0);
            }
            index = mediaCodec.dequeueOutputBuffer(bufferInfo, 1000);

            while (index >= 0 && isRecoding) {
                ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(index);
                byte[] outData = new byte[bufferInfo.size];
                //编码好的数据放入到outputBuffer中
                outputBuffer.get(outData);
                if (startTime == 0) {
                    //微秒转毫秒
                    startTime = bufferInfo.presentationTimeUs / 1000;
                }
                rtmpPackage = new RTMPPackage();
                rtmpPackage.setBuffer(outData);
                //音频数据
                rtmpPackage.setType(RTMPPackage.RTMP_PACKET_TYPE_AUDIO_DATA);
                //设置时间戳
                long tms = (bufferInfo.presentationTimeUs / 1000) - startTime;
                rtmpPackage.setTms(tms);
                screenLive.addPackage(rtmpPackage);
                mediaCodec.releaseOutputBuffer(index, false);
                index = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);

            }
        }
    }
}
